package com.example.service;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import com.example.entity.Document;
import com.example.repository.DocumentRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 文档业务逻辑层
 * 提供完整的增删改查和搜索功能
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DocumentService {

    private final DocumentRepository documentRepository;
    private final ElasticsearchClient elasticsearchClient;

    /**
     * 初始化索引（如果不存在）
     */
    public void initIndex() {
        try {
            ExistsRequest existsRequest = ExistsRequest.of(e -> e.index("documents"));
            boolean exists = elasticsearchClient.indices().exists(existsRequest).value();

            if (!exists) {
                CreateIndexRequest createRequest = CreateIndexRequest.of(c -> c
                        .index("documents")
                        .mappings(m -> m
                                .properties("title", p -> p
                                        .text(t -> t
                                                .analyzer("ik_max_word")
                                                .searchAnalyzer("ik_smart")))
                                .properties("content", p -> p
                                        .text(t -> t
                                                .analyzer("ik_max_word")
                                                .searchAnalyzer("ik_smart")))
                                .properties("author", p -> p
                                        .text(t -> t
                                                .analyzer("ik_smart")
                                                .fields("keyword", f -> f
                                                        .keyword(k -> k))))
                                .properties("tags", p -> p
                                        .keyword(k -> k))
                                .properties("createTime", p -> p
                                        .date(d -> d
                                                .format("yyyy-MM-dd HH:mm:ss")))
                                .properties("updateTime", p -> p
                                        .date(d -> d
                                                .format("yyyy-MM-dd HH:mm:ss")))
                                .properties("readCount", p -> p
                                        .integer(i -> i))
                                .properties("status", p -> p
                                        .integer(i -> i))
                        )
                );

                elasticsearchClient.indices().create(createRequest);
                log.info("索引 'documents' 创建成功");
            } else {
                log.info("索引 'documents' 已存在");
            }
        } catch (IOException e) {
            log.error("初始化索引失败", e);
        }
    }

    /**
     * 保存单个文档
     */
    public Document save(Document document) {
        if (document.getId() == null) {
            document.setId(UUID.randomUUID().toString());
        }
        document.setUpdateTime(LocalDateTime.now());
        return documentRepository.save(document);
    }

    /**
     * 批量保存文档
     */
    public void saveAll(List<Document> documents) {
        documents.forEach(doc -> {
            if (doc.getId() == null) {
                doc.setId(UUID.randomUUID().toString());
            }
            doc.setUpdateTime(LocalDateTime.now());
        });
        documentRepository.saveAll(documents);
    }

    /**
     * 批量保存（使用原生客户端）
     */
    public void bulkSave(List<Document> documents) {
        try {
            BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
            
            for (Document doc : documents) {
                if (doc.getId() == null) {
                    doc.setId(UUID.randomUUID().toString());
                }
                doc.setUpdateTime(LocalDateTime.now());
                
                bulkBuilder.operations(op -> op
                    .index(idx -> idx
                        .index("documents")
                        .id(doc.getId())
                        .document(doc)
                    )
                );
            }
            
            BulkResponse response = elasticsearchClient.bulk(bulkBuilder.build());
            if (response.errors()) {
                log.error("批量保存存在错误");
            } else {
                log.info("批量保存成功，处理了 {} 条记录", documents.size());
            }
        } catch (IOException e) {
            log.error("批量保存失败", e);
        }
    }

    /**
     * 根据ID查找文档
     */
    public Optional<Document> findById(String id) {
        return documentRepository.findById(id);
    }

    /**
     * 获取所有文档
     */
    public Iterable<Document> findAll() {
        return documentRepository.findAll();
    }

    /**
     * 分页获取文档
     */
    public Page<Document> findAll(Pageable pageable) {
        return documentRepository.findAll(pageable);
    }

    /**
     * 根据状态分页查询
     */
    public Page<Document> findByStatus(Integer status, Pageable pageable) {
        return documentRepository.findByStatus(status, pageable);
    }

    /**
     * 更新文档
     */
    public Document update(Document document) {
        document.setUpdateTime(LocalDateTime.now());
        return documentRepository.save(document);
    }

    /**
     * 删除文档
     */
    public void deleteById(String id) {
        documentRepository.deleteById(id);
    }

    /**
     * 删除所有文档
     */
    public void deleteAll() {
        documentRepository.deleteAll();
    }

    /**
     * 简单搜索 - 使用Repository方法
     */
    public List<Document> findByTitle(String title) {
        return documentRepository.findByTitle(title);
    }

    /**
     * 根据作者搜索
     */
    public List<Document> findByAuthor(String author) {
        return documentRepository.findByAuthor(author);
    }

    /**
     * 根据标签搜索
     */
    public List<Document> findByTags(List<String> tags) {
        return documentRepository.findByTagsIn(tags);
    }

    /**
     * 全文搜索 - 在标题和内容中搜索
     */
    public Page<Document> search(String keyword, Pageable pageable) {
        return documentRepository.searchByTitleOrContent(keyword, pageable);
    }

    /**
     * 多字段搜索
     */
    public Page<Document> multiFieldSearch(String keyword, Pageable pageable) {
        return documentRepository.multiFieldSearch(keyword, pageable);
    }

    /**
     * 高级搜索 - 使用原生客户端
     */
    public List<Document> advancedSearch(String keyword) {
        try {
            SearchRequest searchRequest = SearchRequest.of(s -> s
                .index("documents")
                .query(q -> q
                    .bool(b -> b
                        .should(sh -> sh
                            .match(m -> m
                                .field("title")
                                .query(keyword)
                                .boost(2.0f)))  // 标题权重更高
                        .should(sh -> sh
                            .match(m -> m
                                .field("content")
                                .query(keyword)))
                        .should(sh -> sh
                            .match(m -> m
                                .field("author")
                                .query(keyword)))
                    )
                )
                .highlight(h -> h
                    .fields("title", f -> f.preTags("<em>").postTags("</em>"))
                    .fields("content", f -> f.preTags("<em>").postTags("</em>"))
                )
                .size(50)  // 限制返回数量
            );

            SearchResponse<Document> response = elasticsearchClient.search(searchRequest, Document.class);
            
            return response.hits().hits().stream()
                    .map(Hit::source)
                    .collect(Collectors.toList());
        } catch (IOException e) {
            log.error("高级搜索失败", e);
            return List.of();
        }
    }

    /**
     * 聚合查询 - 按作者统计文档数量
     */
    public void aggregateByAuthor() {
        try {
            SearchRequest searchRequest = SearchRequest.of(s -> s
                .index("documents")
                .size(0)  // 只要聚合结果，不要文档
                .aggregations("authors", a -> a
                    .terms(t -> t
                        .field("author.keyword")
                        .size(10)
                    )
                )
            );

            SearchResponse<Document> response = elasticsearchClient.search(searchRequest, Document.class);
            
            log.info("按作者统计结果：");
            // 获取聚合结果
            Aggregate authorsAgg = response.aggregations().get("authors");

            // 安全的类型检查和访问
            if (authorsAgg.isSterms()) {
                authorsAgg.sterms().buckets().array()
                        .forEach(bucket ->
                                log.info("作者：{}，文档数：{}", bucket.key().stringValue(), bucket.docCount())
                        );
            } else if (authorsAgg.isLterms()) {
                authorsAgg.lterms().buckets().array()
                        .forEach(bucket ->
                                log.info("作者：{}，文档数：{}", bucket.key(), bucket.docCount())
                        );
            } else {
                log.warn("未知的聚合类型：{}", authorsAgg._kind());
            }
        } catch (IOException e) {
            log.error("聚合查询失败", e);
        }
    }

    /**
     * 统计文档总数
     */
    public long count() {
        return documentRepository.count();
    }

    /**
     * 检查文档是否存在
     */
    public boolean existsById(String id) {
        return documentRepository.existsById(id);
    }
}